package dao

import (
	"common/biz"
	"common/logs"
	"context"
	"core/models/db"
	"core/models/entity"
	"core/repo"
	"fmt"
	"framework/game"
	"framework/msError"
	"go.mongodb.org/mongo-driver/bson"
	"gorm.io/gorm"
	"time"
)

type ActivityDao struct {
	repo *repo.Manager
}

func (d *ActivityDao) ActivityList(ctx context.Context) *[]db.ActivityHasManyCondition {
	data := new([]db.ActivityHasManyCondition)
	d.repo.DB.Client.WithContext(ctx).Model(db.Activity{}).
		Where("shows=?", true).
		Preload("ActivityCondition", func(db *gorm.DB) *gorm.DB {
			return db.Where("shows=?", true)
		}).
		Preload("ActivityCondition.ActivityConditionReward").
		Preload("ActivityCondition.ActivityConditionReward.Types").
		Find(data)
	return data
}

func (d *ActivityDao) MongoIsReward(ctx context.Context, uid, activityID, inviteID uint) bool {
	collection := d.repo.Mongo.Db.Collection("activity_receive_log")
	count, err := collection.CountDocuments(ctx, bson.D{
		{"uid", uid},
		{"activityID", activityID},
		{"inviteID", inviteID},
	})
	if err != nil || count <= 0 {
		return false
	}
	return true
}

func (d *ActivityDao) GetActivityInfo(ctx context.Context, id uint) *db.Activity {
	data := new(db.Activity)
	d.repo.DB.Client.WithContext(ctx).Model(data).
		Where("id=? AND shows=?", id, true).
		First(data)
	return data
}

func (d *ActivityDao) GetActivityConditionInfo(ctx context.Context, activityID, inviteID uint) *db.ActivityCondition {
	data := new(db.ActivityCondition)
	d.repo.DB.Client.WithContext(ctx).Model(data).
		Where("id=? AND activity_id=? AND shows=?", inviteID, activityID, true).
		First(data)
	return data
}

func (d *ActivityDao) GetActivityConditionReward(ctx context.Context, activityID, inviteID uint) *[]db.ActivityConditionRewardHasOneType {
	data := new([]db.ActivityConditionRewardHasOneType)
	d.repo.DB.Client.WithContext(ctx).Model(db.ActivityConditionReward{}).
		Where("activity_id=? AND invite_id=?", activityID, inviteID).
		Preload("Types").
		Find(data)
	return data
}

func (d *ActivityDao) ActivityReceive(ctx context.Context, uid uint, reward *[]db.ActivityConditionRewardHasOneType) *msError.Error {
	//_db := d.repo.DB.Client.WithContext(ctx)
	//tx := _db.Begin()
	//_mdb := d.repo.Mongo
	//mtx, _ := _mdb.Client.StartSession()
	//_ = mtx.StartTransaction()
	//defer mtx.EndSession(ctx)
	//tableLog := "activity_receive_log"
	//var err error
	//for _, v := range *reward {
	//	//1.添加材料到仓库
	//	switch v.Types.Type {
	//	case 1:
	//		starship := &db.WarehouseStarship{
	//			UID:       uid,
	//			TypeID:    v.TypeID,
	//			EnergyNum: int(v.Energy),
	//		}
	//		err = _db.Model(starship).Create(starship).Error
	//	case 2:
	//		build := &db.WarehouseBuild{
	//			UID:    uid,
	//			TypeID: v.TypeID,
	//			Energy: v.Energy,
	//		}
	//		err = _db.Model(build).Create(build).Error
	//	case 3:
	//		material := new(db.WarehouseMaterialHasOneType)
	//		_db.Model(db.WarehouseMaterial{}).Where("uid=? AND type_id=?", uid, v.TypeID).Preload("Types").First(&material)
	//		if material == nil || material.ID == 0 {
	//			err = tx.Model(db.WarehouseMaterial{}).Create(&db.WarehouseMaterial{
	//				UID:    uid,
	//				TypeID: v.TypeID,
	//				Num:    v.Num,
	//			}).Error
	//			_db.Model(db.WarehouseMaterial{}).Where("uid=? AND type_id=?", uid, v.TypeID).Preload("Types").First(&material)
	//		} else {
	//			err = tx.Model(db.WarehouseMaterial{}).Where("uid=? AND type_id=?", uid, v.TypeID).Update("num", gorm.Expr("num+?", v.Num)).Error
	//		}
	//		if err != nil {
	//			logs.Error("[userHandler]用户%d ActivityReceive err:材料添加失败 req=%v,dbErr=%v", uid, v, err)
	//			tx.Rollback()
	//			_ = mtx.AbortTransaction(ctx)
	//			return biz.SqlError
	//		}
	//		// TODO 3.添加材料记录
	//		materialLog := &entity.MaterialLog{
	//			UID:        uid,
	//			WID:        material.ID,
	//			TypeID:     material.TypeID,
	//			TypeName:   material.Types.Name,
	//			TypeImg:    material.Types.Img,
	//			TypeModule: material.Types.Module,
	//			//LinkID:     fmt.Sprintf("%d", resource.ID),
	//			LinkTable: fmt.Sprintf("m_%v", tableLog),
	//			Ago:       material.Num,
	//			Num:       v.Num,
	//			After:     material.Num + v.Num,
	//			Remarks:   "活动-拉新-领取",
	//			AddTime:   time.Now().Format(time.DateTime),
	//		}
	//		_, err = _mdb.Db.Collection("material_log").InsertOne(ctx, materialLog)
	//	}
	//	if err != nil {
	//		logs.Error("[userHandler]用户%d ActivityReceive err:添加材料变更记录失败 req=%v,dbErr=%v", uid, v, err)
	//		tx.Rollback()
	//		_ = mtx.AbortTransaction(ctx)
	//		return biz.SqlError
	//	}
	//	//2.添加领取记录
	//	log := entity.ActivityReceiveLog{
	//		UID:        uid,
	//		ActivityID: v.ActivityID,
	//		InviteID:   v.InviteID,
	//		RewardID:   v.ID,
	//		Num:        v.Num,
	//		Energy:     v.Energy,
	//		TypeID:     v.TypeID,
	//		TypeName:   v.Types.Name,
	//		TypeImg:    v.Types.Img,
	//		TypeModule: v.Types.Module,
	//		AddTime:    time.Now().Format(time.DateTime),
	//	}
	//	_, err = _mdb.Db.Collection(tableLog).InsertOne(ctx, &log)
	//	if err != nil {
	//		logs.Error("[userHandler]用户%d ActivityReceive err:添加材料变更记录失败 req=%v,dbErr=%v", uid, log, err)
	//		tx.Rollback()
	//		_ = mtx.AbortTransaction(ctx)
	//		return biz.SqlError
	//	}
	//}
	//_ = mtx.CommitTransaction(ctx)
	//tx.Commit()
	return nil
}

func (d *ActivityDao) ContributeReceive(ctx context.Context, uid, id, typeID uint, num int64) *msError.Error {
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	_mdb := d.repo.Mongo
	mtx, _ := _mdb.Client.StartSession()
	_ = mtx.StartTransaction()
	defer mtx.EndSession(ctx)
	tableLog := "activity_contribute_receive_log"
	var err error
	//1.扣除role的对应数量
	role := new(db.Role)
	if typeID == 15 {
		err = tx.Model(role).Where("uid=?", uid).Update("income_xj", gorm.Expr("income_xj-?", num)).Error
	} else {
		err = tx.Model(role).Where("uid=?", uid).Update("income_xy", gorm.Expr("income_xy-?", num)).Error
	}
	if err != nil {
		logs.Error("[userHandler]用户%d ActivityReceive err:扣除贡献值失败 %d", uid, num)
		tx.Rollback()
		return biz.SqlError
	}
	//2.添加领取的收益
	material := new(db.WarehouseMaterialHasOneType)
	_db.Model(db.WarehouseMaterial{}).Where("uid=? AND type_id=?", uid, typeID).Preload("Types").First(&material)
	err = tx.Model(db.WarehouseMaterial{}).Where("uid=? AND type_id=?", uid, typeID).Update("num", gorm.Expr("num+?", num)).Error
	if err != nil {
		logs.Error("[userHandler]用户%d ActivityReceive err:添加领取的收益失败 dbErr=%v", uid, err)
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return biz.SqlError
	}
	// TODO 3.添加材料记录
	materialLog := &entity.MaterialLog{
		UID:        uid,
		WID:        material.ID,
		TypeID:     material.TypeID,
		TypeName:   material.Types.Name,
		TypeImg:    material.Types.Img,
		TypeModule: material.Types.Module,
		//LinkID:     fmt.Sprintf("%d", resource.ID),
		LinkTable: fmt.Sprintf("m_%v", tableLog),
		Ago:       material.Num,
		Num:       num,
		After:     material.Num + num,
		Remarks:   "活动-贡献值-领取",
		AddTime:   time.Now().Format(time.DateTime),
	}
	_, err = _mdb.Db.Collection("material_log").InsertOne(ctx, materialLog)
	if err != nil {
		logs.Error("[userHandler]用户%d ActivityReceive err:添加材料记录失败 dbErr=%v", uid, err)
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return biz.SqlError
	}
	//4.添加领取记录
	_, err = _mdb.Db.Collection(tableLog).InsertOne(ctx, &entity.ActivityContributeReceiveLog{
		UID:         uid,
		ActivityID:  id,
		Num:         num,
		TypeID:      material.TypeID,
		TypeName:    material.Types.Name,
		TypeImg:     material.Types.Img,
		TypeModule:  material.Types.Module,
		ReceiveTime: time.Now().Format(time.DateTime),
	})
	if err != nil {
		logs.Error("[userHandler]用户%d ActivityReceive err:添加领取记录失败 dbErr=%v", uid, err)
		tx.Rollback()
		_ = mtx.AbortTransaction(ctx)
		return biz.SqlError
	}
	_ = mtx.CommitTransaction(ctx)
	tx.Commit()
	return nil
}

// activityUserLevel 把本人身份改为有效用户
func (d *ActivityDao) activityUserLevel(ctx context.Context, uid uint, module string) {
	logs.Info("[Goods]用户%d pay info:修改上级身份 req=%v", uid)
	_db := d.repo.DB.Client.WithContext(ctx)
	tx := _db.Begin()
	conf := game.Conf.ActivityConfig[module].Value
	myUser := new(db.UserHasOneRole)
	user := new(db.User)
	_db.Model(user).Where("id=?", uid).Preload("Role").First(myUser)
	logs.Info("[Goods]用户%d pay info:修改本人和上级身份 req=%v", uid, myUser)
	if myUser.Role.LevelID != db.RoleNone {
		logs.Warn("[Goods]用户%d pay err:用户状态不是零时用户 req=%v", uid, myUser)
		//本人身份不是临时用户返回
		return
	}
	myLevel := db.RoleZs
	pid := myUser.Pid
	//var pid uint
	//_db.Model(db.User{}).Where("id=?", uid).Select("pid").Scan(&pid)
	var count int64
	//本人下方的人数
	_db.Model(user).Joins("left join starship_role ON starship_role.uid=starship_user.id").
		Where("starship_user.pid=? AND starship_role.level_id>=? AND starship_user.deleted_at IS NULL", uid, myLevel).
		Count(&count)
	if count > int64(conf["lz_invite_num"].Val.(float64)) {
		myLevel = db.RoleLz
	}
	//1.修改本人身份
	role := new(db.Role)
	err := tx.Model(role).Where("uid=? AND level_id=?", uid, db.RoleNone).Update("level_id", myLevel).Error
	if err != nil {
		logs.Error("[Goods]用户%d pay err:修改本人身份错误 req=%v,dbErr=%v", uid, myUser, err)
		return
	}
	if pid <= 0 { //无上级
		logs.Warn("[Goods]用户%d pay err:无上级 req=%v", uid, myUser)
		tx.Commit()
		return
	}
	//2.查看上级等级
	var level db.RoleLevel
	_db.Model(role).Where("uid=?", pid).Select("level_id").Scan(&level)
	var upgradation db.RoleLevel
	var confName string
	if level == db.RoleNone || level == db.RoleJz {
		logs.Warn("[Goods]用户%d pay err:上级身份为零时用户或界主 req=%v,pReq=%v", uid, user, level)
		//上级如果是无效用户或界主无需操作
		tx.Commit()
		return
	}
	//上级下方的人数
	_db.Model(user).Joins("left join starship_role ON starship_role.uid=starship_user.id").
		Where("starship_user.pid=? AND starship_role.level_id>=? AND starship_user.deleted_at IS NULL", pid, level).
		Count(&count)
	switch level {
	case db.RoleZs:
		confName = "lz_invite_num"
		upgradation = db.RoleLz
		break
	case db.RoleLz:
		confName = "yz_invite_num"
		upgradation = db.RoleYz
		break
	case db.RoleYz:
		confName = "jz_invite_num"
		upgradation = db.RoleJz
		break
	}
	if count >= int64(conf[confName].Val.(float64)) {
		//满足升级条件
		err = tx.Model(role).Where("uid=?", pid).Update("level_id", upgradation).Error
		if err != nil {
			logs.Error("[Goods]用户%d pay err:修改上级身份错误 req=%v,pReq=%v,dbErr=%v", uid, user, upgradation, err)
			tx.Rollback()
			return
		}
	}

	tx.Commit()
}

func NewActivityDao(m *repo.Manager) *ActivityDao {
	return &ActivityDao{
		repo: m,
	}
}
